package loader

import (
	"fmt"
	"strconv"
	"kumachan/standalone/util/richtext"
	"kumachan/interpreter/lang/common/source"
	"kumachan/interpreter/lang/textual/parser"
)


type Error struct {
	Context   context
	Concrete  ErrorContent
}
type ErrorContent interface { LoaderError() }

func (e E_ReadModuleFailed) LoaderError() {}
type E_ReadModuleFailed struct {
	FilePath  string
	Message   string
}
func (e E_ParseFailed) LoaderError() {}
type E_ParseFailed struct {
	ParserError  *parser.Error
}
func (e E_DepNameDuplicate) LoaderError() {}
type E_DepNameDuplicate struct {
	ImportName  string
}
func (e E_DepModDuplicate) LoaderError() {}
type E_DepModDuplicate struct {
	ModuleName  string
}
func (e E_DepModCircular) LoaderError() {}
type E_DepModCircular struct {
	ModuleName  string
}
func (e E_DepModConflict) LoaderError() {}
type E_DepModConflict struct {
	ModuleName  string
	FilePath1   string
	FilePath2   string
}

func (err *Error) DescribeError() richtext.Block {
	var msg richtext.Block
	const NORMAL = richtext.TAG_ERR_NORMAL
	const INLINE = richtext.TAG_ERR_INLINE
	msg.WriteLine("**")
	switch e := err.Concrete.(type) {
	case E_ReadModuleFailed:
		msg.WriteSpan("Failed to read module from", NORMAL)
		msg.WriteSpan(e.FilePath, INLINE)
		msg.WriteLine(fmt.Sprintf("reason: %s", e.Message), NORMAL)
	case E_ParseFailed:
		msg.Append(e.ParserError.Message())
	case E_DepNameDuplicate:
		msg.WriteSpan("Duplicate dependency name", NORMAL)
		msg.WriteSpan(strconv.Quote(e.ImportName), INLINE)
	case E_DepModDuplicate:
		msg.WriteSpan("Duplicate import of module", NORMAL)
		msg.WriteSpan(strconv.Quote(e.ModuleName), INLINE)
	case E_DepModCircular:
		msg.WriteSpan("Circular import of module", NORMAL)
		msg.WriteSpan(strconv.Quote(e.ModuleName), INLINE)
	case E_DepModConflict:
		msg.WriteSpan("The id", NORMAL)
		msg.WriteSpan(strconv.Quote(e.ModuleName), INLINE)
		msg.WriteSpan("is used by both source files", NORMAL)
		msg.WriteSpan(e.FilePath2, INLINE)
		msg.WriteSpan("and", NORMAL)
		msg.WriteSpan(e.FilePath1, INLINE)
	default:
		panic("unknown error kind")
	}
	return msg
}
func (err *Error) Message() richtext.Block {
	var ctx = err.Context
	return ctx.WrapErrorBlock(err.DescribeError())
}
func (err *Error) Error() string {
	return err.Message().RenderPlainText()
}
func (err *Error) ToSourceError() (*source.Error, bool) {
	var ctx = err.Context
	if (ctx.ImportPoint != source.Location {}) {
		return &source.Error {
			Location: ctx.ImportPoint,
			Content:  err,
		}, true
	} else {
		return nil, false
	}
}


